#include "HttpCookie.h"
#include <sstream>
#include <stdio.h>
#include <string.h>

using namespace xnet;

HttpCookie::HttpCookie(const std::string& fullPathFilename):
	cookieFilename_(fullPathFilename)
{

}

void HttpCookie::readFile()
{
	std::string strFile = getStringFromFile(cookieFilename_);
	if (strFile.empty()) return;

	std::vector<std::string> cookieVec;
	std::stringstream stream(strFile);
	std::string item;

	while (std::getline(stream, item, '\n'))
	{
		cookieVec.push_back(item);
	}
	if (cookieVec.empty()) return;

	cookies_.clear();

	for (auto& cookie : cookieVec)
	{
		if (cookie.empty()) continue;

		if (cookie.find("#HttpOnly_") != std::string::npos)
		{
			cookie.substr(10);
		}

		if (cookie[0] == '#') continue;

		CookieInfo co;
		std::stringstream streamInfo(cookie);
		std::vector<std::string> elems;
		std::string line;

		while (std::getline(streamInfo, line, '\t'))
		{
			elems.push_back(line);
		}

		co.domain = elems[0];
		if (co.domain[0] == '.')
		{
			co.domain = co.domain.substr(1);
		}
		co.tailMatch	= (strcmp("TRUE", elems[1].data()) == 0) ? true : false;
		co.path			= elems[2];
		co.secure		= (strcmp("TRUE", elems[3].data()) == 0) ? true : false;
		co.expires		= elems[4];
		co.name			= elems[5];
		co.value		= elems[6];

		cookies_.push_back(co);
	}
}

std::string HttpCookie::getStringFromFile(const std::string& fullPathFilename)
{
	std::string result;
	if (fullPathFilename.empty()) return result;

	FILE* fp = fopen(fullPathFilename.data(), "r");
	if (fp)
	{
		char buf[64 * 1024];
		size_t readSize = 0;

		while (true)
		{
			readSize = fread(buf, sizeof(char), sizeof(buf), fp);
			if (readSize > 0)
			{
				result.append(buf, readSize);
			}
			else
			{
				if (errno)
				{
					fprintf(stderr, "getStringFromFile() failed! %s\n", strerror(errno));
				}
				break;
			}
		}
	}
	else
	{
		int savedErrno = errno;
		fprintf(stderr, "getStringFromFile() failed! %s\n", strerror(savedErrno));
	}
	fclose(fp);

	return result;
}

void HttpCookie::writeFile()
{
	FILE* out = fopen(cookieFilename_.data(), "w");
	fputs("# Netscape HTTP Cookie File\n"
		  "# http://curl.haxx.se/docs/http-cookies.html\n"
		  "# This file was generated by HttpClient! Edit at your own risk.\n"
		  "# Test HttpClient cookie write",
		  out);

	std::string line;
	for (auto& item : cookies_)
	{
		line.clear();
		line.append(item.domain);
		line.append(1, '\t');
		item.tailMatch ? line.append("TRUE") : line.append("FALSE");
		line.append(1, '\t');
		line.append(item.path);
		line.append(1, '\t');
		item.secure ? line.append("TRUE") : line.append("FALSE");
		line.append(1, '\t');
		line.append(item.expires);
		line.append(1, '\t');
		line.append(item.name);
		line.append(1, '\t');
		line.append(item.value);

		fputs(line.data(), out);
	}

	fclose(out);
}

const std::vector<CookieInfo>* HttpCookie::getCookies() const
{
	return &cookies_;
}

const CookieInfo* HttpCookie::getMatchCookie(const std::string& url) const
{
	for (auto& cookie : cookies_)
	{
		if (url.find(cookie.domain) != std::string::npos)
		{
			return &cookie;
		}
	}

	return nullptr;
}

void HttpCookie::updateOrAddCookie(const CookieInfo& cookie)
{
	for (auto& item : cookies_)
	{
		if (cookie.domain == item.domain)
		{
			item = cookie;
			return;
		}
	}

	cookies_.push_back(cookie);
}